package simpledb.common;

import simpledb.storage.*;

import java.io.*;
import java.util.*;

/**
 * 用于测试和实现随机功能的辅助类。
 *
 * 提供了一些常用的工具方法，例如创建 TupleDesc、构造 Tuple 对象、生成空的 HeapFile 等，
 * 主要用于简化测试代码的编写。
 */
public class Utility {

    /**
     * 创建一个长度为 len 的 Type 数组，所有元素都为 Type.INT_TYPE。
     *
     * @param len 数组长度
     * @return 包含 INT_TYPE 的数组
     */
    public static Type[] getTypes(int len) {
        Type[] types = new Type[len];
        for (int i = 0; i < len; ++i)
            types[i] = Type.INT_TYPE;
        return types;
    }

    /**
     * 创建一个长度为 len 的字符串数组，每个字符串为 val + i。
     * 如果 val 为 null，则字段名为 "null0", "null1" 等。
     *
     * @param len 数组长度
     * @param val 字段名前缀
     * @return 带编号的字符串数组
     */
    public static String[] getStrings(int len, String val) {
        String[] strings = new String[len];
        for (int i = 0; i < len; ++i)
            strings[i] = val + i;
        return strings;
    }

    /**
     * 创建一个包含 n 个整型字段的 TupleDesc。
     * 每个字段命名为 name+i（如 name1, name2）。
     *
     * @param n 字段数量
     * @param name 字段名前缀
     * @return 新建的 TupleDesc 对象
     */
    public static TupleDesc getTupleDesc(int n, String name) {
        return new TupleDesc(getTypes(n), getStrings(n, name));
    }

    /**
     * 创建一个只包含 INT_TYPE 类型字段的 TupleDesc。
     *
     * @param n 字段数量
     * @return 新建的 TupleDesc 对象
     */
    public static TupleDesc getTupleDesc(int n) {
        return new TupleDesc(getTypes(n));
    }

    /**
     * 创建一个包含单个 IntField 的元组，并设置其 RecordId。
     *
     * @param n 字段值
     * @return 包含指定值的元组
     */
    public static Tuple getHeapTuple(int n) {
        Tuple tup = new Tuple(getTupleDesc(1));
        tup.setRecordId(new RecordId(new HeapPageId(1, 2), 3));
        tup.setField(0, new IntField(n));
        return tup;
    }

    /**
     * 根据 int 数组创建一个元组，并设置固定 RecordId。
     *
     * @param tupdata 元组字段值数组
     * @return 包含指定数据的元组
     */
    public static Tuple getHeapTuple(int[] tupdata) {
        Tuple tup = new Tuple(getTupleDesc(tupdata.length));
        tup.setRecordId(new RecordId(new HeapPageId(1, 2), 3));
        for (int i = 0; i < tupdata.length; ++i)
            tup.setField(i, new IntField(tupdata[i]));
        return tup;
    }

    /**
     * 创建一个宽度为 width 的元组，每个字段值为 n，并设置固定 RecordId。
     *
     * @param n 所有字段的值
     * @param width 元组宽度（字段数）
     * @return 新建的元组
     */
    public static Tuple getHeapTuple(int n, int width) {
        Tuple tup = new Tuple(getTupleDesc(width));
        tup.setRecordId(new RecordId(new HeapPageId(1, 2), 3));
        for (int i = 0; i < width; ++i)
            tup.setField(i, new IntField(n));
        return tup;
    }

    /**
     * 根据数组创建一个元组，不设置 RecordId。
     *
     * @param tupledata 元组字段值数组
     * @param width 元组宽度
     * @return 新建的元组
     */
    public static Tuple getTuple(int[] tupledata, int width) {
        if (tupledata.length != width) {
            System.out.println("get Hash Tuple has the wrong length~");
            System.exit(1);
        }
        Tuple tup = new Tuple(getTupleDesc(width));
        for (int i = 0; i < width; ++i)
            tup.setField(i, new IntField(tupledata[i]));
        return tup;
    }

    /**
     * 创建一个新的空 HeapFile，并写入一个空页，添加到数据库 Catalog 中。
     *
     * @param path 文件路径
     * @param cols 表中字段数量
     * @return 创建好的 HeapFile 对象
     */
    public static HeapFile createEmptyHeapFile(String path, int cols) throws IOException {
        File f = new File(path);
        // 创建空文件
        FileOutputStream fos = new FileOutputStream(f);
        fos.write(new byte[0]);
        fos.close();

        HeapFile hf = openHeapFile(cols, f);
        HeapPageId pid = new HeapPageId(hf.getId(), 0);

        HeapPage page = null;
        try {
            page = new HeapPage(pid, HeapPage.createEmptyPageData());
        } catch (IOException e) {
            throw new RuntimeException("failed to create empty page in HeapFile");
        }

        hf.writePage(page);
        return hf;
    }

    /**
     * 打开一个 HeapFile 并将其添加到数据库 Catalog 中。
     *
     * @param cols 表中字段数量
     * @param f 文件对象
     * @return 打开的 HeapFile 对象
     */
    public static HeapFile openHeapFile(int cols, File f) {
        TupleDesc td = getTupleDesc(cols);
        HeapFile hf = new HeapFile(f, td);
        Database.getCatalog().addTable(hf, UUID.randomUUID().toString());
        return hf;
    }

    public static HeapFile openHeapFile(int cols, String colPrefix, File f, TupleDesc td) {
        HeapFile hf = new HeapFile(f, td);
        Database.getCatalog().addTable(hf, UUID.randomUUID().toString());
        return hf;
    }

    public static HeapFile openHeapFile(int cols, String colPrefix, File f) {
        TupleDesc td = getTupleDesc(cols, colPrefix);
        return openHeapFile(cols, colPrefix, f, td);
    }

    /**
     * 将整型列表转换为制表符分隔的字符串。
     *
     * @param list 整型列表
     * @return 制表符分隔的字符串
     */
    public static String listToString(List<Integer> list) {
        StringBuilder out = new StringBuilder();
        for (Integer i : list) {
            if (out.length() > 0)
                out.append("\t");
            out.append(i);
        }
        return out.toString();
    }
}
